#!/bin/bash

# Valgrind 内存泄漏检测脚本
# Valgrind 与 ASan 不兼容，需要重新编译

echo "======================================"
echo "Valgrind 内存泄漏检测工具"
echo "======================================"

# 检查 Valgrind 是否安装
if ! command -v valgrind &> /dev/null; then
    echo "错误: 未安装 Valgrind"
    echo "请运行: sudo apt-get install valgrind"
    exit 1
fi

echo "Valgrind 版本: $(valgrind --version)"

# 检查是否需要重新编译
echo -e "\n⚠️  重要提示:"
echo "Valgrind 与 AddressSanitizer 不兼容"
echo "需要关闭 ASan 重新编译项目"
echo ""

read -p "是否现在重新编译? (y/n): " recompile

if [ "$recompile" = "y" ]; then
    echo -e "\n备份当前 CMakeLists.txt..."
    cp CMakeLists.txt CMakeLists.txt.bak

    echo "修改 CMakeLists.txt (注释 ASan 配置)..."

    # 注释掉 ASan 相关行
    sed -i '36s/^/#/' CMakeLists.txt
    sed -i '37s/^/#/' CMakeLists.txt

    echo "重新编译..."
    cd build
    cmake -G Ninja ..
    ninja
    cd ..

    if [ $? -ne 0 ]; then
        echo "编译失败"
        mv CMakeLists.txt.bak CMakeLists.txt
        exit 1
    fi

    echo "✓ 编译完成"
else
    echo "跳过编译，使用现有二进制文件"
    echo "注意: 如果当前编译时启用了 ASan，Valgrind 可能无法正常工作"
fi

# 创建日志目录
LOG_DIR="valgrind_logs"
mkdir -p $LOG_DIR

TIMESTAMP=$(date +%Y%m%d_%H%M%S)
LOG_FILE="${LOG_DIR}/valgrind_${TIMESTAMP}.log"

echo -e "\n[Valgrind 配置]"
echo "日志文件: $LOG_FILE"
echo ""
echo "Valgrind 选项说明:"
echo "  --leak-check=full        : 详细的内存泄漏检测"
echo "  --show-leak-kinds=all    : 显示所有类型的泄漏"
echo "  --track-origins=yes      : 跟踪未初始化值的来源"
echo "  --track-fds=yes          : 跟踪文件描述符"
echo "  --verbose                : 详细输出"

# 询问运行方式
echo -e "\n选择运行方式:"
echo "1. 手动测试 (启动后自行运行客户端，按 Ctrl+C 停止)"
echo "2. 定时测试 (运行指定秒数后自动停止)"
read -p "请选择 (1/2): " choice

# Valgrind 命令
VALGRIND_CMD="valgrind \
    --leak-check=full \
    --show-leak-kinds=all \
    --track-origins=yes \
    --track-fds=yes \
    --verbose \
    --log-file=$LOG_FILE \
    ./build/bin/server_test"

case $choice in
    1)
        echo -e "\n启动服务器 (使用 Valgrind)..."
        echo "⚠️  注意: Valgrind 会显著降低程序运行速度"
        echo "按 Ctrl+C 停止服务器"
        echo ""
        $VALGRIND_CMD
        ;;
    2)
        read -p "运行多少秒后自动停止? [60]: " duration
        duration=${duration:-60}
        echo -e "\n启动服务器，将在 ${duration} 秒后自动停止..."

        $VALGRIND_CMD &
        SERVER_PID=$!

        echo "Valgrind 进程 PID: $SERVER_PID"
        echo "运行时间倒计时: ${duration}s"

        # 倒计时显示
        for ((i=$duration; i>0; i--)); do
            echo -ne "\r剩余时间: ${i}s "
            sleep 1
        done

        echo -e "\n\n发送终止信号..."
        kill -TERM $SERVER_PID 2>/dev/null
        wait $SERVER_PID 2>/dev/null
        ;;
    *)
        echo "无效选择"
        exit 1
        ;;
esac

# 分析报告
echo -e "\n======================================"
echo "检测完成，正在分析报告..."
echo "======================================"

if [ ! -f "$LOG_FILE" ]; then
    echo "错误: 未找到日志文件 $LOG_FILE"
    exit 1
fi

echo -e "\n=== Valgrind 报告摘要 ==="

# 提取关键信息
echo -e "\n[内存泄漏统计]"
grep "LEAK SUMMARY" -A 10 "$LOG_FILE"

echo -e "\n[文件描述符泄漏]"
grep "FILE DESCRIPTORS" -A 5 "$LOG_FILE"

echo -e "\n[内存使用统计]"
grep "total heap usage" "$LOG_FILE"

# 检查是否有泄漏
if grep -q "definitely lost: 0 bytes in 0 blocks" "$LOG_FILE" && \
   grep -q "indirectly lost: 0 bytes in 0 blocks" "$LOG_FILE"; then
    echo -e "\n✓ 未检测到明确的内存泄漏"
else
    echo -e "\n🔴 检测到内存泄漏，详情请查看日志文件"
fi

echo -e "\n完整报告: $LOG_FILE"
echo "查看报告: less $LOG_FILE"

# 询问是否恢复 CMakeLists.txt
if [ "$recompile" = "y" ]; then
    echo -e "\n是否恢复 CMakeLists.txt (重新启用 ASan)? (y/n):"
    read restore
    if [ "$restore" = "y" ]; then
        mv CMakeLists.txt.bak CMakeLists.txt
        echo "✓ 已恢复 CMakeLists.txt"
        echo "记得重新编译以启用 ASan: cd build && cmake -G Ninja .. && ninja"
    fi
fi

echo -e "\n检测结束"
